/***************************************************************************
 创建者: 华磊
 开始时间: 2020.8.14
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2020.5.8 类的具体实现代码编写

 ***************************************************************************
 *  @file x.h
 *  功能:
 *
 *                                                                         *
 ***************************************************************************/
#ifndef ROBOTBASE_H
#define ROBOTBASE_H


//#include "ecatconfig.h"
#include "ecatmotor.h"
#include "ecatio.h"
#include "domparser.h"
#include "robotio.h"
//#include "ecatmasterbase.h"

#include <QMap>
#include <QVector>


enum E_TIME_ROBOT{
    E_TIME_ROBOT_MATH_P2,

    E_TIME_ROBOT_MAX
};

/**
 * @brief The RobotBase class 单个机器人抽象类
 */
class RobotBase : public  DomParser
{
public:
    RobotBase();
    ~RobotBase();


public:
    int getCanopenAxisByAlias(int alias,EcatMotor* motorOut);
    int getMotorVendorId(int axisId, unsigned int &vendorOut);
    int getMotorErrorCode(int axisId, unsigned short &errorCodeOut);
    int getMotorStatusWord(int axisId, unsigned short &statusWordOut);
    int initialMotorControlMode();
    int getMotorControlMode(int axisIndex,E_MOTOR_CONTROL_MODE& modeOut);
    int setMotorControlMode(int axisIndex,E_MOTOR_CONTROL_MODE modeIn);
    int get_ethercat_node_info(int index, S_EcatDevInfo* nodeInfo);
    int add_ethercat_node_info(S_EcatDevInfo* nodeInfo);
    bool getInitialStatus();
    int getDi(int index, bool &diOut);
    int getAi(int index,double& aiOut);
    int getMaganeticDi(QVector<bool> &diOut);

    int initRobotBase(int robotId, QString folder );
    //检查机器报警 ( 放在ethercat处理 )
    int checkError();
    int checkEthercatDeviceError( );
    int checkModbusRtuDeviceError( );
    int checkModbusTcpDeviceError( );
    int checkCanopenDeviceError();

    /**
     * @brief updateEthercatIoData  //更新机器io, 要求周期执行 ( 放在ethercat处理) ecatio到robot io数据映射交换
     * @return   true=io数据更新成功
     */
    bool updateEthercatIoData( );
    void testForDiTrigCount();
    bool updateCanIoData( );
    int updateInputModbusRtuIodata();
    int updateInputModbusTcpIodata();
    int updateOutputModbusRtuIodata();
    int updateOutputModbusTcpIodata();
    /**
     * @brief setServoData //调用算法
     */
    bool setServoData( );
    int initialMotorEncoderValue();//获取编码器线数
    int initialServoParameter();
    int createTimeMeasure( );//创建时间
    int setDcCycle(int cycleTime);


    ///==for api ==================

    EN_BATTERY_STATUS isRobotMotorBatteryOk(int axisId, uint vendorErrorCode);//绝对值电池掉点
    bool setControlWordDebug(unsigned short controlWordIn);
    bool setControlWordDebug_axis(unsigned short controlWordIn,int axisId);
    /**
     * @brief servoOnRobot   ///伺服使能(机器人所有轴).isInitialOkStatus 没有准备好时，不得使能，否则会飞车。
     */
    bool servoOnRobot( );
    bool servoOnRobotAxis( int axisId );
    /**
     * @brief servoSwitch 伺服物理开关 按下/松开
     * @param flag  　ｏｎ＝ｔｒｕｅ
     */
    bool servoSwitch( bool flag );
    /**
     * @brief servoOffRobot   ///关闭伺服(机器人所有轴)
     */
    bool servoOffRobot( );
    bool servoOffRobotAxis( int axisId );
    /**
     * @brief quickStopRobot ///伺服立即停止(机器人所有轴)
     */
    bool quickStopRobot( );
    /**
     * @brief setHomeOffsetRobot  ///零点设定(机器人所有轴)
     * @param valueList
     */
//    int setHomeOffsetRobot( QVector<int>&valueList );
    /**
     * @brief setControlWordRobot 写控制字(机器人所有轴)
     * @param value 控制命令
     */
    bool setControlWordRobot( int value );
    /**
     * @brief getServoDataRobot  ///获取轴的各种数据(机器人所有轴)
     * @return
     */
    QVector<ServoState> getServoDataRobot( );


    /**
     * @brief resetErrorRobot //报警复位(机器人所有轴)
     */
    bool resetErrorRobot();
    /**
     * @brief robotAxisToEthercatNode 获取指定轴的站号
     * @return 1 if ok
     */
    int robotAxisToEthercatNode(int ethercatAxis, int &returnNode ,
                                E_DEVICE_PROTOCOL &protocolOut);
    int deviceAliasToEthercatNode(int deviceAliasIn, int &returnNode ,
                                E_DEVICE_PROTOCOL &protocolOut);
    /**
     * @brief isServoOnRobot   获取机器人伺服ON状态 （所有轴ON才正确）
     */
    bool isServoOnRobot();
    bool isServoOnRobotAxis(int axisId );
    int  getServoOnStatus(QVector<bool> &flagReturn);
    /**
     * @brief setMotorPositionRobot 写编码器的值
     * @param vPos 写值
     */
    bool setMotorPositionRobot(QVector<int> vPos);
    /**
     * @brief setMotorPositionAxis 写编码器的值
     * @param axis
     * @param pos 写值
     */
    bool setMotorPositionAxis(int ethercatAxis, int pos);
    /**
     * @brief getMotorPositionRobot  计算后的编码（带零点偏移）
     * @return 编码器的值
     */
    QVector<int> getMotorPositionRobot();
    /**
     * @brief getMotorPositionRobot_real  读上来的真实编码器值 （真实编码器值）
     * @return 编码器的值
     */
    QVector<int> getMotorPositionRobot_real( );

    // void setTestSpeed();
    void test_demo();//测试运行（testForm控制界面控制）



private:
    bool isAxisNumberCorrect();
    EN_BATTERY_STATUS isRobotMotorBatteryOk_ecat_motor(int axisId, uint vendorErrorCode);//绝对值电池掉点
    bool isRobotMotorBattoryOk_modbus_rtu_motor();//绝对值电池掉点
    bool isRobotMotorBattoryOk_modbus_tcp_motor();//绝对值电池掉点

    /**
        * @brief checkIoMapStatus  ///检查映射有效性
        * @return  true=ok
        */
    int checkIoMapStatus();
    bool isIoMapOk();
    /**
         * @brief readRobotInfoXml  读取robotInfo.xml
         * @param xmlfile
         * @return
         */
    int readRobotInfoXml( QString xmlfile );

    /**
     * @brief addMsg  , 添加消息反馈    // 如果放在ethercat处理 , 用log缓存信息。外部周期处理
     * @param messageLevel
     * @param componentName
     * @param messageType
     * @param messageCode
     * @param robotId
     * @param parameter1
     * @param parameter2
     * @param parameter3
     * @param parameter4
     */
    void addMsg( int messageLevel,
                 std::string componentName,
                 std::string messageType,
                 int messageCode,
                 int _robotId,
                 int parameter1 = 0,
                 int parameter2 = 0,
                 int parameter3 = 0,
                 int parameter4 = 0 );


//-----------------------------------------------------------


public:
    RobotInfo robotInfo;

    QVector<LogicMotor*> logicAxis;//逻辑轴
    volatile int size_logicalAxisArryCopy;
    LogicMotor* logicalAxisArryCopy[1000];////逻辑轴,副本，为了解决线程安全问题。
    QVector<EcatMotor*> ethercatAxis;//逻辑轴顺序开始１,按逻辑轴小到大排序
    QVector<EcatMotor*> modbusRtuAxis;//逻辑轴顺序开始２,按逻辑轴小到大排序
    QVector<EcatMotor*> modbusTcpAxis;//逻辑轴顺序开始3,按逻辑轴小到大排序
    QVector<EcatMotor*> canopenAxis;//逻辑轴顺序开始4,按逻辑轴小到大排序

    QVector<EcatIo*> ethercatIoModule;
    QVector<EcatIo*> canopenIoModule;
    QVector<EcatIo*> modbusRtuIoModule;
    QVector<EcatIo*> modbusTcpIoModule;

    RobotIo* logicRobotIo;//逻辑ＩＯ

    bool isRobotServoOnFlag; // HMI伺服控制标志位
    bool isWarningState; // 警告标志
    bool isFaultOccurred;// 报警标志/故障发生
    bool isMapOk; //检测映射有效性标志
    bool isLinkOk;//检测映射有效性标志

    ///==for ethercat master and EcatBusManager

    volatile int get_data_flag;//获取到有效的算法数据
    ///==end

    ///==for 测试接口 ===========
    volatile int test_acceleration_set;//加速时间设置值/ms
    volatile int test_target_increment_set;//目标增量设置值
    volatile int test_axis_set;//指定轴(-1=all axis)
    volatile int test_dir_set;//(0=反向, 1=正向)
    volatile bool test_run_set;
    volatile int test_dir_ms;
    int test_count;



private://测试接口
    int test_acceleration;//加速时间/S
    int test_target_increment_tmp;//目标增量
    int test_dir_tmp;
    ///==end  测试接口
    ///
    /// private:
    int cycle_us;
    int cycle_ns;
    int timer_id[20];//time tool用，时间stamp
    pthread_mutex_t ioThreadLock;//线程锁
    pthread_cond_t cond;//线程同步信号
    pthread_mutexattr_t attr;//线程锁参数
    QMap<int, EcatIo* >  ecatIoDeviceDataMap;// <nodeId, 指向 etherfcat 数据的指针>
    QMap<int, EcatIo* >  canioDeviceDataMap;// <nodeId, 指向 canio EcatIo的指针>
    volatile bool isQuickStopCtl;//急停控制标志( true=不发送/位置/速速/扭矩? )
//    volatile bool isSetHomeOffsetOk;//原点标定成功标志
    QVector<int> tmp_homeoffset;//原点数据缓存
    FILE *fpServoDataFile;//写位置到文件
    bool fpFlush;
    unsigned int servo_data_id;
    bool isInitialOk;

    QVector<S_EcatDevInfo*> ethercat_node_info;//ethercat 节点信息

    int tmpTickCount;//驱动器第一次启动，好像会误报警告：不支持设定控制模式
    int errorCount;
};



#endif // ROBOTBASE_H
